home *** CD-ROM | disk | FTP | other *** search
- unit Collect;
- { Collection classes for Delphi 2.0
- Alin Flaider, 1996
- aflaidar@datalog.ro }
-
- interface
- uses Windows, Classes, Sysutils;
-
- const
- coIndexError = -1; { Index out of range }
- coOverflow = -2; { Overflow }
- coUnderflow = -3; { Underflow }
-
- type
- CollException = class(Exception);
-
- TCollection = class( TObject)
- private { return item at index position }
- function At( Index : integer) : Pointer;
- { replace item at index position}
- procedure AtPut( Index : integer; Item : Pointer);
- protected
- It : PPointerList; { array of pointers }
- Limit : integer; { Current Allocated size of array}
- Delta : integer; {Number of items by which the collection grows when full}
- { deletes item at index position }
- procedure AtDelete (Index : integer);
- { generates CollException }
- procedure Error (Code,Info : Integer); virtual;
- { destroys specified Item; override this method if Item is not
- a descendant of TObject }
- procedure FreeItem (Item : Pointer); virtual;
- public
- Count : integer; {Current Number of Items}
- constructor create(aLimit, aDelta : integer);
- {before deallocating object it disposes all items and the storage array}
- destructor destroy; override;
- {inserts Item at specified position }
- procedure AtInsert( Index : integer; Item : Pointer);
- {deletes and disposes Item at specified position}
- procedure AtFree(Index: Integer);
- {deletes Item}
- procedure Delete( Item : Pointer);
- {deletes all Items without disposing them }
- procedure DeleteAll;
- {formerly Free, renamed to Clear to avoid bypassing inherited TObject.Free;
- deletes and disposes Item }
- procedure Clear(Item: Pointer);
- {finds first item that satisfies condition specified in
- function Test( Item: pointer): boolean}
- function FirstThat( Test : Pointer) : Pointer;
- {finds last item that satisfies condition specified in
- function Test( Item: pointer): boolean}
- function LastThat( Test : Pointer) : Pointer;
- {calls procedure Action( Item: pointer) for each item in collection}
- procedure ForEach( Action : Pointer);
- {disposes all items; set counter to zero}
- procedure FreeAll;
- {finds position of Item using a linear search}
- function IndexOf( Item : Pointer) : integer; virtual;
- {inserts Item at the end of collection}
- procedure Insert( Item : Pointer); virtual;
- {packs collection by removing nil Items}
- procedure Pack;
- {expands array of pointers }
- procedure SetLimit( aLimit : integer);virtual;
- {direct access to items through position}
- property Items[Index: integer]: pointer read At write AtPut; default;
- end;
-
- TSortedCollection = class(TCollection)
- Duplicates: boolean; {if true, rejects item whose key already exists}
- {override this method to specify relation bewtween two keys
- 1 if Key1 comes after Key2, -1 if Key1 comes before Key2,
- 0 if Key1 is equivalent to Key2}
- function Compare (Key1,Key2 : Pointer): Integer; virtual; abstract;
- {returns key of Item}
- function KeyOf (Item : Pointer): Pointer; virtual;
- {finds index of item by calling Search}
- function IndexOf (Item : Pointer): integer; virtual;
- {finds item required position and performs insertion }
- procedure Insert (Item : Pointer); virtual;
- {finds index of item by performing an optimised search}
- function Search (key : Pointer; Var Index : integer) : Boolean; virtual;
- end;
-
- implementation
-
- constructor TCollection.Create(ALimit, ADelta: Integer);
- begin
- inherited Create;
- Limit:= 0;
- Delta:=aDelta;
- Count:=0;
- It := nil;
- SetLimit( ALimit);
- end;
-
- destructor TCollection.Destroy;
- begin
- FreeAll;
- SetLimit(0);
- inherited Destroy;
- end;
-
- function TCollection.At(Index: Integer): Pointer;
- begin
- If Index > pred(Count) then
- begin
- Error(coIndexError,0);
- Result :=nil;
- end
- else Result := It^[Index];
- end;
-
- procedure TCollection.AtPut(Index: Integer; Item: Pointer);
- begin
- if (Index < 0) or (Index >= Count) then
- Error(coIndexError,0)
- else It^[Index] := Item;
- end;
-
- procedure TCollection.AtDelete(Index: Integer);
- var p: pointer;
- begin
- if (Index < 0) or (Index >= Count) then
- begin
- Error(coIndexError,0);
- exit;
- end;
- if Index < pred(Count) then
- move( It^[succ(Index)], It^[Index], (count-index)*sizeof(pointer));
- Dec(Count);
- end;
-
- procedure TCollection.AtInsert( Index: integer; Item: pointer);
- var i : integer;
- begin
- if (Index < 0) or ( Index > Count) then
- begin
- Error(coIndexError,0);
- exit;
- end;
- if Limit = Count then
- begin
- if Delta = 0 then
- begin
- Error(coOverFlow,0);
- exit;
- end;
- SetLimit( Limit+Delta);
- end;
- If Index <> Count then {move compensates for overlaps}
- move( It^[Index], It^[Index+1], (count - index)*sizeof(pointer));
- It^[Index] := Item;
- Inc(Count);
- end;
-
- procedure TCollection.Delete( Item: pointer);
- begin
- AtDelete(Indexof(Item));
- end;
-
- procedure TCollection.DeleteAll;
- begin
- Count:=0
- end;
-
- procedure TCollection.Error(Code, Info: Integer);
- begin
- case Code of
- coIndexError: raise CollException.Create('Collection error; wrong index: '+IntToStr(Info));
- coOverflow: raise CollException.Create('Collection overflow - cannot grow!');
- coUnderflow: raise CollException.Create('Collection underflow - cannot shrink!');
- end
- end;
-
- function TCollection.FirstThat(Test: Pointer): Pointer;
- type
- tTestFunc = function( p : pointer) : Boolean;
- var i : integer;
- begin
- Result := nil;
- for i := 0 to pred(count) do
- if tTestFunc(test)(It^[i]) then begin
- Result := It[i];
- break
- end
- end;
-
- procedure TCollection.ForEach(Action: Pointer);
- type
- tActionProc = procedure(p : pointer);
- var i : integer;
- begin
- for i := 0 to pred(Count) do
- tActionProc(Action)(It^[i]);
- end;
-
- procedure TCollection.Clear(Item: Pointer);
- begin
- Delete(Item);
- FreeItem(Item);
- end;
-
- procedure TCollection.FreeAll;
- var i : integer;
- begin
- for I := 0 to Count - 1 do FreeItem(At(I));
- Count := 0;
- end;
-
- procedure TCollection.FreeItem(Item: Pointer);
- begin
- if Item <> nil then TObject(Item).Free;
- end;
-
- function TCollection.IndexOf(Item: Pointer): integer;
- var i : integer;
- begin
- Result := -1;
- for i := 0 to pred(count) do
- if Item = It^[i] then begin
- Result := i;
- break
- end
- end;
-
- procedure TCollection.Insert(Item: Pointer);
- begin
- AtInsert(Count,Item);
- end;
-
- function TCollection.LastThat(Test: Pointer): pointer;
- type
- tTestFunc = function( p : pointer) : Boolean;
- var i : integer;
- begin
- Result := nil;
- for i := pred(count) downto 1 do
- if tTestFunc(test)(It^[i]) then begin
- Result := It^[i];
- break
- end
- end;
-
- procedure TCollection.Pack;
- var i: integer;
- begin
- for i := pred(count) downto 0 do if It^[i] = nil then AtDelete(i);
- end;
-
- procedure TCollection.SetLimit(ALimit: Integer);
- begin
- if (ALimit < Count) then Error( coUnderFlow , 0);
- if ALimit <> Limit then
- begin
- ReallocMem( It, ALimit* SizeOf(Pointer));
- Limit := ALimit;
- end;
- end;
-
- function TSortedCollection.IndexOf(Item: Pointer): Integer;
- var
- i: Integer;
- begin
- IndexOf := -1;
- if Search(KeyOf(Item), i) then
- begin
- if Duplicates then
- while (i < Count) and (Item <> It^[I]) do Inc(i);
- if i < Count then IndexOf := i;
- end;
- end;
-
- procedure TSortedCollection.Insert(Item: Pointer);
- var i : integer;
- begin
- if not Search(KeyOf(Item), I) or Duplicates then AtInsert(I, Item);
- end;
-
- function TSortedCollection.KeyOf(Item: Pointer): Pointer;
- begin
- Result := Item;
- end;
-
- function TSortedCollection.Search;
- var
- L, H, I, C: Integer;
- begin
- Search := False;
- L := 0;
- H := Count - 1;
- while L <= H do
- begin
- I := (L + H) shr 1;
- C := Compare(KeyOf(It^[I]), Key);
- if C < 0 then L := I + 1 else
- begin
- H := I - 1;
- if C = 0 then
- begin
- Search := True;
- if not Duplicates then L := I;
- end;
- end;
- end;
- Index := L;
- end;
-
- procedure TCollection.AtFree(Index: Integer);
- var
- Item: Pointer;
- begin
- Item := At(Index);
- AtDelete(Index);
- FreeItem(Item);
- end;
-
- end.